/**
 * 文件名：****.java
 * 版权：Copyright Lightkit All Rights Reserved.
 * 描述：*****
 */
package com.lightkits.wms.domain.saleticket.impl;

import com.lightkits.common.TransactionValidate;
import com.lightkits.common.db.entity.BdTag;
import com.lightkits.common.db.entity.FndItemBase;
import com.lightkits.common.db.entity.FndOrganizationBase;
import com.lightkits.common.db.entity.FndWorker;
import com.lightkits.common.db.entity.WmSaleTicketLine;
import com.lightkits.common.db.entity.WmSalesTicket;
import com.lightkits.common.db.entity.event.BdEvent;
import com.lightkits.common.db.entity.event.BdEventRecord;
import com.lightkits.framework.common.exception.LightKitsBizException;
import com.lightkits.framework.common.logging.Logger;
import com.lightkits.framework.common.logging.LoggerFactory;
import com.lightkits.framework.common.model.CheckResult;
import com.lightkits.framework.common.model.IResult;
import com.lightkits.framework.common.utility.json.JsonUtil;
import com.lightkits.framework.common.utility.object.ObjectUtil;
import com.lightkits.framework.common.utility.validate.IntegrityValidator;
import com.lightkits.wms.domain.saleticket.CreateChangeParams;
import com.lightkits.wms.domain.saleticket.CreateSaleEventService;
import com.lightkits.wms.domain.saleticket.CreateSaleParamsService;
import com.lightkits.wms.domain.saleticket.CreateSaleTicketService;
import com.lightkits.wms.domain.saleticket.model.SaleConstrant;
import com.lightkits.wms.domain.saleticket.repo.WmSaleTicketLineService;
import com.lightkits.wms.domain.saleticket.repo.WmSaleTicketService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventRecordService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventService;
import com.lightkits.wms.domain.tagservice.UseTagParamsService;
import com.lightkits.wms.dto.saleticket.model.SaleTicketHeadDto;
import com.lightkits.wms.dto.saleticket.model.SaleTicketLineDto;
import com.lightkits.wms.dto.tagservice.model.CancelTagDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 创建售货单
 *
 * @author jing.wei@hand-china.com.
 * @date 2019/5/31 5:42.
 **/
@Service
public class CreateSaleTicketServiceImpl implements CreateSaleTicketService {
    private final Logger logger = LoggerFactory.getLogger(CreateSaleTicketServiceImpl.class);

    private final WmSaleTicketLineService saleTicketLineService;
    private final WmSaleTicketService saleTicketService;
    private final BdEventRecordService bdEventRecordService;
    private final BdEventService bdEventService;
    private final CreateSaleParamsService createSaleParamsService;
    private final CreateSaleEventService createSaleEventService;
    private final UseTagParamsService useTagParamsService;

    @Autowired
    public CreateSaleTicketServiceImpl(WmSaleTicketLineService saleTicketLineService,
                                       WmSaleTicketService saleTicketService,
                                       BdEventRecordService bdEventRecordService,
                                       BdEventService bdEventService,
                                       CreateSaleParamsService createSaleParamsService,
                                       CreateSaleEventService createSaleEventService,
                                       UseTagParamsService useTagParamsService, CreateChangeParams createChangeParams) {
        this.saleTicketLineService = saleTicketLineService;
        this.saleTicketService = saleTicketService;
        this.bdEventRecordService = bdEventRecordService;
        this.bdEventService = bdEventService;
        this.createSaleParamsService = createSaleParamsService;
        this.createSaleEventService = createSaleEventService;
        this.useTagParamsService = useTagParamsService;
        this.createChangeParams = createChangeParams;
    }

    private final CreateChangeParams createChangeParams;

    /**
     * 售货单参数校验
     *
     * @param headDto  售货单头信息
     * @param lineDtos 售货单行信息
     * @return IResult
     **/
    private IResult checkParams(SaleTicketHeadDto headDto,
                                List<SaleTicketLineDto> lineDtos) {
        try {
            //售货单头信息必输校验
            IntegrityValidator.begin().validate(headDto.getOrgId(), "Organization Id")
                    .validate(headDto.getCurrency(), "Curreny Type")
                    .validate(headDto.getDelieveyWays(), "Deleivery Ways")
                    .validate(headDto.getGoodTotal(), "Goods Total")
                    .validate(headDto.getInvoice(), "Invoice");
            //数字格式的校验
            Pattern pattern = Pattern.compile(SaleConstrant.PATTERN_NUMBER);
            if (!pattern.matcher(headDto.getGoodTotal()).matches()) {
                return IResult.fail("The Goods Total is invalid");
            }
            Pattern pattern1 = Pattern.compile(SaleConstrant.PATTERN_NUMBER_LENGTH);
            if (!ObjectUtil.isNullOrEmpty(headDto.getFreight())
                    && !pattern1.matcher(headDto.getFreight()).matches()) {
                return IResult.fail("The Frieght is invalid");
            }
            if (!ObjectUtil.isNullOrEmpty(headDto.getPriceTotal())
                    && !pattern.matcher(headDto.getPriceTotal()).matches()) {
                return IResult.fail("The Price Total is invalid");
            }
            //售货单头参数有效性校验
            TransactionValidate check = TransactionValidate
                    .beginValidity(FndOrganizationBase.class);
            check.checkIdValidity(
                    ObjectUtil.toString(headDto.getOrgId()),
                    "ORGANIZATION_ID");
            check = TransactionValidate
                    .beginValidity(FndWorker.class);
            check.checkIdValidity(
                    ObjectUtil.toString(headDto.getWorkerId()),
                    "ID");
            //售货单行的必输参数校验
            lineDtos.forEach(line -> {
                IntegrityValidator.begin().validate(line.getItemId(), "Item Id")
                        .validate(line.getTagId(), "Tag Id")
                        .validate(line.getTotalPrice(), "Total Price");
                //售货单行的参数数字格式校验
                if (!pattern.matcher(line.getTotalPrice()).matches()) {
                    throw new LightKitsBizException("The Total Price is invalid");
                }
                if (!ObjectUtil.isNullOrEmpty(line.getMarketPrice())
                        && !pattern.matcher(line.getMarketPrice()).matches()) {
                    throw new LightKitsBizException("The Markers Price is invalid");
                }
                //售货单行的参数有效性校验
                TransactionValidate check1 = TransactionValidate
                        .beginValidity(FndItemBase.class);
                check1.checkIdValidity(
                        ObjectUtil.toString(line.getItemId()),
                        "ITEM_ID");

                check1 = TransactionValidate
                        .beginValidity(BdTag.class);
                check1.checkIdValidity(
                        ObjectUtil.toString(line.getTagId()),
                        "ID");
            });
        } catch (LightKitsBizException e) {
            return e.result();
        }
        return IResult.success();
    }

    /**
     * 售货单的创建
     *
     * @param headDto  售货单头参数
     * @param lineDtos 售货单行参数
     * @return IResult
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public IResult createSaleTicket(SaleTicketHeadDto headDto, List<SaleTicketLineDto> lineDtos) {
        //检查参数
        IResult result = this.checkParams(headDto, lineDtos);
        if (!result.isSuccessful()) {
            return result;
        }
        //创建事件并插值
        CheckResult checkResult = createSaleEventService.createEvent(headDto, "WM_SALE_ORDER");
        if (!checkResult.isSuccessful() || checkResult.getData() == null) {
            throw new LightKitsBizException(checkResult.getMessage());
        }
        BdEvent event = (BdEvent) checkResult.getData();
        Boolean eventFlag = bdEventService.insert(event);
        if (!eventFlag) {
            throw new LightKitsBizException("Insert Sale Ticket Event Failed");
        }
        //创建售货单头并插值
        WmSalesTicket ticketHead = createSaleParamsService.createSaleHead(headDto);
        Boolean headFlag = saleTicketService.insert(ticketHead);
        if (!headFlag) {
            throw new LightKitsBizException("Insert Sale Ticket Head Failed");
        }

        List<WmSaleTicketLine> ticketLines = createSaleParamsService.createSaleLine(lineDtos,
                ticketHead.getId(), ticketHead.getCurrency());

        Boolean linesFlag = saleTicketLineService.insertBatch(ticketLines);
        if (!linesFlag) {
            throw new LightKitsBizException("Insert Sale Ticket Lines Failed");
        }
        //创建售货单头行的快照
        List<BdEventRecord> bdEventRecords = new ArrayList<>();
        //创建售货单头快照
        BdEventRecord record = createSaleEventService.createEventRecord("SALE_TICKET_HEAD",
                headDto.getGoodTotal(),
                event.getId(),
                ticketHead.getId(),
                "", JsonUtil.toString(ticketHead));
        bdEventRecords.add(record);
        //创建是失效条码
        List<CancelTagDto> cancelTagDtos = createChangeParams.createSimCancelTag(ticketLines, event);
        IResult result1 = useTagParamsService.cancelTag(cancelTagDtos);
        if (!result1.isSuccessful()) {
            throw new LightKitsBizException(result1.getMessage());
        }
        //创建售货单行的快照
        ticketLines.forEach(line -> {
            BdEventRecord bdEventRecord = createSaleEventService.createEventRecord("SALE_TICKET_LINE",
                    line.getTotalPrice().toString(), event.getId(),
                    line.getId(), "", JsonUtil.toString(line));
            bdEventRecords.add(bdEventRecord);
        });
        //快照插值
        Boolean recordFlaag = bdEventRecordService.insertBatch(bdEventRecords);
        if (!recordFlaag) {
            throw new LightKitsBizException("Insert Sale Ticket ReCords Failed");
        }

        return IResult.success();
    }
}
